[小ネタ]CloudWatch Agent で Agent 自身のプロセス監視を行ない Lambda + SSM RunCommand で自動復旧を行う
アノテーション株式会社のあのふじたです
前回の記事では CloudWatch Agent をインストールしている EC2 の Agent 自身のプロセス監視はどうすれば良いのかという疑問が湧くことがあったので試して見ました。
今回はこの自動復旧を設定するにはどうしたら良いのかちょっと考えてみます。
アラート状態の条件と復旧手順
- EC2 が running であること
- CloudWatch Agent のプロセスが起動していないこと
2つの条件が必要なので複合アラームが望ましいと考えます。
また、アラート時に SSM Run Command を利用して CloudWatch Agent のプロセス起動を行うために Lambda を利用するのが簡単です。
昔は CloudWatch → SNS → Lambda で同様のことを実現していましたがアップデートにより CloudWatch から直接 Lambda が実行できるようになりました。
[アップデート] Amazon CloudWatch のアラームで、実行アクションに Lambda 関数を直接指定出来るようになりました
今回想定する Lambda の動作は
- インスタンスの状態を確認し、インスタンスが実行中(running)か判定する
- running の場合のみ SSM Run Command を利用して CloudWatch Agent のプロセス起動を行う
の条件で作成します。
作業手順
1. EC2 の インスタンスステータスのチェック アラームの作成
- 設定したい EC2 の ステータスとアラームタブへ移動し、
アクション
からステータスチェックアラームの作成
- そのままデフォルトで作成すると
awsec2-<ec2instanceid>-GeaterThanOrEqualToThreshould-StatusCheckFailed
のアラーム名で作成されます。
2. CloudWatch Agent のプロセス監視のアラーム作成
※ 前提条件:前回のブログの CloudWatchAgent のプロセス監視を設定済であること
- マネジメントコンソール → CloudWatch → 全てのメトリクス → CWAgent → exe,host,pid_finder
- 対象のEC2の amazon-cloudwat にチェック
- 数式を追加 → 全ての関数 FILL
- FILL(m1,0) に変更
※ データ未送信時の監視速度を早めるため Fill関数を利用して欠落データを0埋めします。 詳細仕様は以下をご確認ください
Metric Math を使用する
- FILL を設定した e1 のアクションのベルアイコンをクリックしアラートの作成を行います
- 期間 1分
- 静的, 以下, 0
- その他設定: アラームを実行するデータポイント 3/5
- 欠落データを不正(しきい値を超えている)として処理
- 次へ
- 通知は削除しておきます
- 次へ
- 任意のアラーム名にします。(例:CloudWatchAgent-StatusCheck-Alarm)
3. Lambda の作成
- Lambda → 関数 → 関数の作成
- 任意の関数名を付けます (例: CWAgent-Restart-LambdaFunction)
- 今回は
Nodejs20.x
で作成します。 - 実行ロールはデフォルトで作成で構いません。
import { SSMClient, SendCommandCommand } from "@aws-sdk/client-ssm"; import { EC2Client, DescribeInstancesCommand } from "@aws-sdk/client-ec2"; const ssmClient = new SSMClient({}); const ec2Client = new EC2Client({}); export const handler = async (event) => { // イベントデータから alarmRule を取得 const alarmRule = event.alarmData.configuration.alarmRule; // alarmRule からインスタンス ID を抽出する正規表現 const instanceIdRegex = /awsec2-(i-\w+)/; // alarmRule に対して正規表現を適用し、インスタンス ID を抽出 const match = alarmRule.match(instanceIdRegex); if (match && match[1]) { // インスタンス ID をログに出力 const instanceId = match[1]; console.log('Extracted Instance ID:', instanceId); try { // EC2 インスタンスの状態を確認 const describeParams = { InstanceIds: [instanceId], }; const describeCommand = new DescribeInstancesCommand(describeParams); const describeData = await ec2Client.send(describeCommand); const instanceState = describeData.Reservations[0].Instances[0].State.Name; if (instanceState === 'running') { // SSM Run Command パラメータ const ssmParams = { InstanceIds: [instanceId], DocumentName: 'AWS-RunShellScript', Parameters: { commands: [ 'sudo systemctl restart amazon-cloudwatch-agent' ] } }; // SSM Run Command を実行 const ssmCommand = new SendCommandCommand(ssmParams); const ssmData = await ssmClient.send(ssmCommand); console.log('SSM Run Command Success:', ssmData); } else { console.log(`Instance ${instanceId} is not in running state.`); } } catch (error) { console.error('Error:', error); throw error; } } else { // インスタンス ID が見つからない場合のログ console.log('No Instance ID found in alarmRule.'); } // レスポンスを返す const response = { statusCode: 200, body: JSON.stringify('All Done.'), }; return response; };
4. Lambda の権限の追加や修正
- 作成した LambdaRole に以下ポリシーアタッチ
- AmazonEC2ReadOnlyAccess
- AmazonSSMFullAccess
- リソースベースのポリシーステートメント
- アクセス権限を追加
- プリンシパル: lambda.alarms.cloudwatch.amazonaws.com
- アクション: lambda:InvokeFunction
5. 複合アラームの作成
- 以下にチェックを入れ
複合アラームの作成
- CloudWatchAgent-Proccess-Running
- awsec2-
-GreaterThanOrEqualToThreshold-StatusCheckFailed
- 以下に書き換える
NOT ALARM("awsec2-<ec2instanceid>-GeaterThanOrEqualToThreshould-StatusCheckFailed") AND ALARM("CloudWatchAgent-Proccess-Running")
- 次へ
- 通知 削除
- Lambda アクション の追加
-
- で作成した関数(例: CWAgent-Restart-LambdaFunction)を指定
- で作成した関数(例: CWAgent-Restart-LambdaFunction)を指定
- 次へ
- 任意のアラーム名(例: CWAgent-Proccess-NotRunning)を入力
- 次へ
- 複合アラームの作成
- 複合アラームの作成
6. 動作確認
EC2 にログインし CloudWatch Agent を停止します。
sh-5.2$ sudo pstree -pa |grep cloudwatch |-amazon-cloudwat,1446 -config/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.to | | | | |-grep,2980 cloudwatch sh-5.2$ sudo systemctl stop amazon-cloudwatch-agent sh-5.2$ sudo pstree -pa |grep cloudwatch | | | | |-grep,3065 cloudwatch sh-5.2$
しばらくすると複合アラームがアラーム状態になった後OKになっていることが確認できました。
別のプロセスIDで起動されていることを確認
sh-5.2$ sudo pstree -pa |grep cloudwatch |-amazon-cloudwat,3139 -config/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.to | | | | |-grep,3541 cloudwatch
SSM Run Command の実行ログも(/var/log/amazon/ssm/amazon-ssm-agent.log
)念の為確認
2024-xx-xx xx:xx:31 INFO [ssm-agent-worker] [MessageService] [MGSInteractor] Sending reply { "additionalInfo": { "agent": { "lang": "en-US", "name": "amazon-ssm-agent", "os": "", "osver": "1", "ver": "" }, "dateTime": "2024-xx-xxTxx:38:31.997Z", "runId": "", "runtimeStatusCounts": { "Success": 1 } }, "documentStatus": "InProgress", "documentTraceOutput": "", "runtimeStatus": { "aws:runShellScript": { "status": "Success", "code": 0, "name": "aws:runShellScript", "output": "", "startDateTime": "2024-xx-xxTxx:38:31.726Z", "endDateTime": "2024-xx-xxTxx:38:31.996Z", "outputS3BucketName": "", "outputS3KeyPrefix": "", "stepName": "", "standardOutput": "", "standardError": "" } } }
成功しているようです。
まとめとして
インスタンスを停止する際に2つのメトリクスの時間差で誤動作する場合がありますが、EC2 が running であるか確認することで概ね復旧する動作が実現できました。
複数台の監視については様々な手法があるのでまた調べようと思います。
アノテーション株式会社について
アノテーション株式会社はクラスメソッドグループのオペレーション専門特化企業です。
サポート・運用・開発保守・情シス・バックオフィスの専門チームが、最新 IT テクノロジー、高い技術力、蓄積されたノウハウをフル活用し、お客様の課題解決を行っています。
当社は様々な職種でメンバーを募集しています。「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、アノテーション株式会社 採用サイトをぜひご覧ください。